package com.rickpan.storage.monitor;

import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.Timer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 存储操作指标监控服务
 * 收集和记录存储操作的各种性能指标
 */
@Service
public class StorageMetricsService {
    
    private static final Logger logger = LoggerFactory.getLogger(StorageMetricsService.class);
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    // 操作计数器
    private final ConcurrentHashMap<String, Counter> operationCounters = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, Counter> errorCounters = new ConcurrentHashMap<>();
    
    // 操作计时器
    private final ConcurrentHashMap<String, Timer> operationTimers = new ConcurrentHashMap<>();
    
    // 数据传输量统计
    private final ConcurrentHashMap<String, DistributionSummary> dataSizeDistributions = new ConcurrentHashMap<>();
    
    // 活跃操作数量
    private final AtomicLong activeOperations = new AtomicLong(0);
    private final Gauge activeOperationsGauge;
    
    // 累计统计
    private final LongAdder totalUploadedBytes = new LongAdder();
    private final LongAdder totalDownloadedBytes = new LongAdder();
    private final LongAdder totalOperations = new LongAdder();
    
    public StorageMetricsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // 注册活跃操作数量指标
        this.activeOperationsGauge = Gauge.builder("storage.operations.active", activeOperations, AtomicLong::get)
            .description("当前活跃的存储操作数量")
            .register(meterRegistry);

        // 注册累计统计指标
        Gauge.builder("storage.bytes.uploaded.total", totalUploadedBytes, LongAdder::sum)
            .description("累计上传字节数")
            .register(meterRegistry);

        Gauge.builder("storage.bytes.downloaded.total", totalDownloadedBytes, LongAdder::sum)
            .description("累计下载字节数")
            .register(meterRegistry);

        Gauge.builder("storage.operations.total", totalOperations, LongAdder::sum)
            .description("累计操作总数")
            .register(meterRegistry);
    }
    
    /**
     * 记录操作开始
     * 
     * @param operation 操作类型
     * @param storageType 存储类型
     * @return 计时器样本
     */
    public Timer.Sample startOperation(String operation, String storageType) {
        activeOperations.incrementAndGet();
        totalOperations.increment();
        
        // 获取或创建操作计时器
        Timer timer = getOperationTimer(operation, storageType);
        
        logger.debug("开始存储操作: operation={}, storageType={}, activeOps={}", 
                    operation, storageType, activeOperations.get());
        
        return Timer.start(meterRegistry);
    }
    
    /**
     * 记录操作完成
     * 
     * @param sample 计时器样本
     * @param operation 操作类型
     * @param storageType 存储类型
     * @param success 是否成功
     * @param dataSize 数据大小（字节）
     */
    public void recordOperationComplete(Timer.Sample sample, String operation, String storageType, 
                                      boolean success, long dataSize) {
        activeOperations.decrementAndGet();
        
        // 记录操作耗时
        Timer timer = getOperationTimer(operation, storageType);
        long durationNanos = sample.stop(timer);
        Duration duration = Duration.ofNanos(durationNanos);
        
        // 记录操作计数
        if (success) {
            getOperationCounter(operation, storageType, "success").increment();
        } else {
            getOperationCounter(operation, storageType, "failure").increment();
            getErrorCounter(operation, storageType).increment();
        }
        
        // 记录数据传输量
        if (dataSize > 0) {
            getDataSizeDistribution(operation, storageType).record(dataSize);
            
            // 更新累计统计
            if ("upload".equals(operation) || "store".equals(operation)) {
                totalUploadedBytes.add(dataSize);
            } else if ("download".equals(operation)) {
                totalDownloadedBytes.add(dataSize);
            }
        }
        
        logger.debug("完成存储操作: operation={}, storageType={}, success={}, duration={}ms, dataSize={}, activeOps={}", 
                    operation, storageType, success, duration.toMillis(), dataSize, activeOperations.get());
    }
    
    /**
     * 记录错误
     * 
     * @param operation 操作类型
     * @param storageType 存储类型
     * @param errorType 错误类型
     */
    public void recordError(String operation, String storageType, String errorType) {
        getErrorCounter(operation, storageType, errorType).increment();
        
        logger.warn("存储操作错误: operation={}, storageType={}, errorType={}", 
                   operation, storageType, errorType);
    }
    
    /**
     * 记录分片上传操作
     * 
     * @param duration 操作耗时
     * @param success 是否成功
     * @param chunkSize 分片大小
     * @param chunkIndex 分片索引
     * @param storageType 存储类型
     */
    public void recordChunkUpload(Duration duration, boolean success, long chunkSize, 
                                int chunkIndex, String storageType) {
        // 记录分片上传计时
        Timer.builder("storage.chunk.upload.duration")
            .description("分片上传耗时")
            .tag("storage.type", storageType)
            .tag("success", String.valueOf(success))
            .register(meterRegistry)
            .record(duration);
        
        // 记录分片大小分布
        DistributionSummary.builder("storage.chunk.size")
            .description("分片大小分布")
            .tag("storage.type", storageType)
            .register(meterRegistry)
            .record(chunkSize);
        
        // 记录分片上传计数
        Counter.builder("storage.chunk.upload.count")
            .description("分片上传计数")
            .tag("storage.type", storageType)
            .tag("success", String.valueOf(success))
            .register(meterRegistry)
            .increment();
        
        if (success) {
            totalUploadedBytes.add(chunkSize);
        }
        
        logger.debug("记录分片上传: storageType={}, success={}, chunkSize={}, chunkIndex={}, duration={}ms", 
                    storageType, success, chunkSize, chunkIndex, duration.toMillis());
    }
    
    /**
     * 记录 URL 生成操作
     * 
     * @param duration 操作耗时
     * @param urlType URL类型
     * @param cached 是否使用缓存
     * @param storageType 存储类型
     */
    public void recordUrlGeneration(Duration duration, String urlType, boolean cached, String storageType) {
        Timer.builder("storage.url.generation.duration")
            .description("URL生成耗时")
            .tag("storage.type", storageType)
            .tag("url.type", urlType)
            .tag("cached", String.valueOf(cached))
            .register(meterRegistry)
            .record(duration);
        
        Counter.builder("storage.url.generation.count")
            .description("URL生成计数")
            .tag("storage.type", storageType)
            .tag("url.type", urlType)
            .tag("cached", String.valueOf(cached))
            .register(meterRegistry)
            .increment();
        
        logger.debug("记录URL生成: storageType={}, urlType={}, cached={}, duration={}ms", 
                    storageType, urlType, cached, duration.toMillis());
    }
    
    /**
     * 获取操作计时器
     */
    private Timer getOperationTimer(String operation, String storageType) {
        String key = operation + ":" + storageType;
        return operationTimers.computeIfAbsent(key, k -> 
            Timer.builder("storage.operation.duration")
                .description("存储操作耗时")
                .tag("operation", operation)
                .tag("storage.type", storageType)
                .register(meterRegistry)
        );
    }
    
    /**
     * 获取操作计数器
     */
    private Counter getOperationCounter(String operation, String storageType, String result) {
        String key = operation + ":" + storageType + ":" + result;
        return operationCounters.computeIfAbsent(key, k -> 
            Counter.builder("storage.operation.count")
                .description("存储操作计数")
                .tag("operation", operation)
                .tag("storage.type", storageType)
                .tag("result", result)
                .register(meterRegistry)
        );
    }
    
    /**
     * 获取错误计数器
     */
    private Counter getErrorCounter(String operation, String storageType) {
        return getErrorCounter(operation, storageType, "unknown");
    }
    
    private Counter getErrorCounter(String operation, String storageType, String errorType) {
        String key = operation + ":" + storageType + ":" + errorType;
        return errorCounters.computeIfAbsent(key, k -> 
            Counter.builder("storage.operation.errors")
                .description("存储操作错误计数")
                .tag("operation", operation)
                .tag("storage.type", storageType)
                .tag("error.type", errorType)
                .register(meterRegistry)
        );
    }
    
    /**
     * 获取数据大小分布统计
     */
    private DistributionSummary getDataSizeDistribution(String operation, String storageType) {
        String key = operation + ":" + storageType;
        return dataSizeDistributions.computeIfAbsent(key, k -> 
            DistributionSummary.builder("storage.operation.data.size")
                .description("存储操作数据大小分布")
                .tag("operation", operation)
                .tag("storage.type", storageType)
                .baseUnit("bytes")
                .register(meterRegistry)
        );
    }
    
    /**
     * 获取当前活跃操作数量
     */
    public long getActiveOperationsCount() {
        return activeOperations.get();
    }
    
    /**
     * 获取累计统计信息
     */
    public StorageStats getStorageStats() {
        return new StorageStats(
            totalOperations.sum(),
            totalUploadedBytes.sum(),
            totalDownloadedBytes.sum(),
            activeOperations.get()
        );
    }
    
    /**
     * 存储统计信息
     */
    public static class StorageStats {
        private final long totalOperations;
        private final long totalUploadedBytes;
        private final long totalDownloadedBytes;
        private final long activeOperations;
        
        public StorageStats(long totalOperations, long totalUploadedBytes, 
                          long totalDownloadedBytes, long activeOperations) {
            this.totalOperations = totalOperations;
            this.totalUploadedBytes = totalUploadedBytes;
            this.totalDownloadedBytes = totalDownloadedBytes;
            this.activeOperations = activeOperations;
        }
        
        // Getters
        public long getTotalOperations() { return totalOperations; }
        public long getTotalUploadedBytes() { return totalUploadedBytes; }
        public long getTotalDownloadedBytes() { return totalDownloadedBytes; }
        public long getActiveOperations() { return activeOperations; }
    }
}
